﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PACKETPARSERMAX20.CORE;

namespace PACKETPARSERMAX20.CONSOLE
{
    public static class ConvertOLDSQLiteToSQLite
    {

        public static void Convert(string pSourceDir, string pDestDir)
        {

            string[] files = System.IO.Directory.GetFiles(pSourceDir, "*.sqlite", System.IO.SearchOption.AllDirectories);

            foreach (string file in files)
            {
                //bool tconvert = false;
                //using (var findcon = new System.Data.SQLite.SQLiteConnection())
                //{

                //    findcon.ConnectionString = "Data Source=" + file;
                //    findcon.Open();

                //    using (var tSQLiteCommand = findcon.CreateCommand())
                //    {
                //        tSQLiteCommand.CommandText = "select * from packets limit 1";
                //        using (var tempreader = tSQLiteCommand.ExecuteReader())
                //        {
                //            tconvert = (tempreader.FieldCount == 6);

                //        }
                //    }
                //}

                //if (tconvert)
                //{
                //    ConvertFile(file, pDestDir);
                //}
                //else
                //{
                    RenameFile(file, pDestDir);
                //}
            }
        }
        public static void RenameFile(string pFileName, string pDestDir)
        {

            var eventManager = new EventManager();
            var opcodeFilter = new OpcodeFilter();

            var delete = false;
            var build = 0;
            var AccountName = "";
            var createddate = DateTime.Now;

            using (var definitionprocessor = DefinitionProcessor.LoadDefinitionProcessor(pFileName, eventManager, opcodeFilter))
            {
                if (definitionprocessor != null)
                {
                    build = definitionprocessor.Reader.ClientBuild;
                    AccountName = definitionprocessor.Reader.AccountName;
                    definitionprocessor.Reader.Load();
                    definitionprocessor.Reader.MaxProcessCount = 1;
                    var packet = definitionprocessor.Reader.GetNextPacket();

                    delete = packet == null;

                    if (!delete)
                    {

                        createddate = packet.CreatedDate;

                    }
                }
            }


            if (!delete)
            {
                string dest = string.Format(pDestDir + @"{0}\", build);

                if (!System.IO.Directory.Exists(dest))
                {
                    System.IO.Directory.CreateDirectory(dest);
                }

                string newfile = string.Format(@"{0}{1}_{2}_{3}.sqlite", dest, createddate.ToString("yyyy-MM-dd-HH-mm"), build, AccountName);

                if (System.IO.File.Exists(newfile))
                {
                    System.IO.File.Delete(pFileName);
                    //int i = 1;

                    //while (System.IO.File.Exists(newfile))
                    //{
                    //    newfile = string.Format(@"{0}{1}_{2}_{3}_{4}.sqlite", dest, createddate.ToString("yyyy-MM-dd-HH-mm"), build, AccountName, i);
                    //    i++;
                    //}
                }
                else
                {

                    System.IO.File.Move(pFileName, newfile);
                }
                 
            }
            else
            { System.IO.File.Delete(pFileName); }
        }


        public static void ConvertFile(string pFileName, string pDestDir)
        {


            //                                                             CREATE TABLE sqlite_sequence(name,seq) CREATE TABLE packets (id integer primary key autoincrement, sess_id integer, timestamp datetime, direction integer, opcode integer, data blob)
            //CREATE TABLE header (`key` string primary key, value string) CREATE TABLE sqlite_sequence(name,seq) CREATE TABLE packets (id integer primary key autoincrement,                  timestamp datetime, direction integer, opcode integer, data blob)

            UInt16 _ClientBuild = 0;
            string _accountName = "";
            DateTime logstarted = DateTime.Now;
            bool found = false;
            bool empty = false;

            using (var findcon = new System.Data.SQLite.SQLiteConnection())
            {
                findcon.ConnectionString = "Data Source=" + pFileName;
                findcon.Open();

                using (var tSQLiteCommand = findcon.CreateCommand())
                {
                    tSQLiteCommand.CommandText = "select * from packets limit 5";
                    using (var tempreader = tSQLiteCommand.ExecuteReader())
                    {
                        while (tempreader.Read())
                        {
                            var id = tempreader.GetInt32(0);
                            var sessionid = tempreader.GetInt32(1);
                            logstarted = tempreader.GetDateTime(2);
                            var direction = tempreader.GetInt32(3);
                            var opcode = tempreader.GetInt32(4);
                            var blob = (byte[])tempreader.GetValue(5);

                            if ((Opcodes)opcode == Opcodes.CMSG_AUTH_SESSION)
                            {
                                using (var qs = new PACKETPARSERMAX20.CORE.QuickStream())
                                {
                                    found = true;
                                    qs.Load(blob);

                                    _ClientBuild = qs.ReadUInt16();
                                    var _unknown1 = qs.ReadUInt16();
                                    var _unknown2 = qs.ReadUInt32();
                                    _accountName = qs.ReadString();
                                    // var _clientSeed = qs.ReadUInt32();
                                    break;
                                }
                            }
                        }
                        tempreader.Close();

                        empty = (_ClientBuild == 0);

                    }
                }

                if (!empty)
                {
                    if (!found) throw new Exception("Invalid file");
                    string newdir = string.Format("{0}{1}\\", pDestDir, _ClientBuild);
                    string newfile = string.Format(@"{0}{1}_{2}_{3}.sqlite", newdir, logstarted.ToString("yyyy-MM-dd-HH-mm"), _ClientBuild, _accountName);

                    if (System.IO.File.Exists(newfile)) throw new Exception("File exists");
                    if (!System.IO.Directory.Exists(newdir)) System.IO.Directory.CreateDirectory(newdir);

                    System.Data.SQLite.SQLiteConnection.CreateFile(newfile);

                    var builder = new System.Data.SQLite.SQLiteConnectionStringBuilder();
                    builder.DataSource = newfile;
                    builder.CacheSize = builder.CacheSize * 100;
                    builder.PageSize = builder.PageSize * 100;
                    builder.JournalMode = System.Data.SQLite.SQLiteJournalModeEnum.Off;
                    builder.Pooling = false;

                    DateTime tstart = DateTime.Now;
                    using (var con = new System.Data.SQLite.SQLiteConnection(builder.ConnectionString))
                    {
                        con.Open();

                        //create tables
                        StringBuilder sb = new StringBuilder();

                        sb.AppendLine("create table packets (id integer primary key autoincrement, timestamp datetime, direction integer, opcode integer, data blob);");
                        sb.AppendLine("create table header (key string primary key, value string);");
                        sb.AppendLine(string.Format("insert into header(key, value) values ('clientBuild', '{0}');", _ClientBuild));
                        sb.AppendLine("insert into header(key, value) values ('clientLang', 'enUS');");
                        sb.AppendLine(string.Format("insert into header(key, value) values ('accountName', '{0}');", _accountName));
                        sb.AppendLine("insert into header(key, value) values ('realmName', '');");
                        sb.AppendLine("insert into header(key, value) values ('realmServer', '');");
                        sb.AppendLine("insert into header(key, value) values ('snifferVersion', '');");

                        using (System.Data.SQLite.SQLiteCommand command = con.CreateCommand())
                        {
                            command.CommandText = sb.ToString();
                            command.ExecuteNonQuery();
                        }




                        Console.WriteLine("start processing newfile: {0} filename: {1}", tstart, newfile);

                        try
                        {

                            using (System.Data.SQLite.SQLiteTransaction dbTrans = con.BeginTransaction())
                            {
                                using (System.Data.SQLite.SQLiteCommand command = con.CreateCommand())
                                {
                                    command.CommandText = "insert into packets (timestamp, direction, opcode, data) VALUES (?,?,?,?)";

                                    System.Data.SQLite.SQLiteParameter timestamp = command.CreateParameter();
                                    timestamp.DbType = System.Data.DbType.DateTime;
                                    command.Parameters.Add(timestamp);

                                    System.Data.SQLite.SQLiteParameter direction = command.CreateParameter();
                                    direction.DbType = System.Data.DbType.Int32;
                                    command.Parameters.Add(direction);

                                    System.Data.SQLite.SQLiteParameter opcode = command.CreateParameter();
                                    opcode.DbType = System.Data.DbType.Int32;
                                    command.Parameters.Add(opcode);

                                    System.Data.SQLite.SQLiteParameter data = command.CreateParameter();
                                    data.DbType = System.Data.DbType.Binary;
                                    command.Parameters.Add(data);

                                    using (var tSQLiteCommand = findcon.CreateCommand())
                                    {
                                        tSQLiteCommand.CommandText = "select * from packets ";
                                        using (var tempreader = tSQLiteCommand.ExecuteReader())
                                        {
                                            while (tempreader.Read())
                                            {
                                                var _id = tempreader.GetInt32(0);
                                                var _sessionid = tempreader.GetInt32(1);
                                                var _timestamp = tempreader.GetDateTime(2);
                                                var _direction = tempreader.GetInt32(3);
                                                var _opcode = tempreader.GetInt32(4);
                                                var _blob = (byte[])tempreader.GetValue(5);

                                                try
                                                {
                                                    timestamp.Value = _timestamp;
                                                    direction.Value = _direction;
                                                    opcode.Value = _opcode;
                                                    data.Value = _blob;

                                                    if (command.ExecuteNonQuery() <= 0)
                                                    {
                                                        throw new Exception("record not inserted?");
                                                    }
                                                }
                                                catch (Exception exc)
                                                {
                                                    Console.WriteLine("Error: {0}", exc.Message);
                                                }
                                            }
                                            tempreader.Close();
                                        }
                                    }



                                }

                                dbTrans.Commit();

                            }
                        }
                        catch (Exception exc)
                        {
                            Console.WriteLine("Error: {0}", exc.Message);

                        }

                        con.Close();
                    }

                }
            }

            System.IO.File.Delete(pFileName);

        }

        public static bool WritePacket(PACKETPARSERMAX20.CORE.Packet packet, System.Data.SQLite.SQLiteConnection con)
        {
            bool failed = false;
            try
            {



                using (System.Data.SQLite.SQLiteCommand command = con.CreateCommand())
                {
                    try
                    {
                        //"insert into packets (timestamp, direction, opcode, data) 
                        //" values 
                        //(datetime("+String.valueOf(packet.date.getTime()/1000)+",'unixepoch'),
                        //"+packet.direction+",
                        //"+packet.opcode+",
                        //X'"+ByteBufferConverter.getHexRepresentation(packet.payload, false)+"');";



                        command.Parameters.AddWithValue("@timestamp", packet.CreatedDate);
                        command.Parameters.AddWithValue("@direction", packet.Direction);
                        command.Parameters.AddWithValue("@opcode", packet.Opcode);
                        command.Parameters.AddWithValue("@data", packet.Data);

                        command.ExecuteNonQuery();
                    }
                    catch (Exception exc)
                    {
                        Console.WriteLine("Error: {0}", exc.Message);
                    }
                }


            }
            catch (Exception exc)
            {
                Console.WriteLine("Error: {0}", exc.Message);
                failed = true;
            }

            return failed;
        }


    }
}
